#pragma once
#include<iostream>
#include<unordered_set>
#include"IO.h"
#include"MemUtil.h"
#include"ResourceManage.h"
using namespace std;

class BlockDel :public ResourceManage{
public:    //由于record太重量，在del记录里太浪费内存。因此在这里采用现使用现创建。
    unordered_set<int32_t> delIndSet;
    unordered_set<int32_t> snapShot;
    vector<int32_t> additionDelIndList;
    int indSize = sizeof (int32_t);

    void initData(char* fileData, const long& fileLen){
        delIndSet.clear();
        additionDelIndList.clear();
        int32_t cpyNum;
        for(int32_t i = 0; i < fileLen; i += indSize){
            memcpy(&cpyNum, &fileData[i], indSize);
            delIndSet.insert(cpyNum);
            snapShot.insert(cpyNum);
        }
    }

    char* getAllDataBuffer(){
        char* buffer = new char[delIndSet.size() * indSize];
        int ind = 0;
        for(const int32_t& it : delIndSet){
            memcpy(&buffer[ind], &it, indSize);
            ind += indSize;
        }
        return buffer;
    }

    virtual void readFromDisk(){
        fstream f;
        if(!IOUtil::initFstreamIfExist(f, resourceInfo.getFullPath())){
            return;     //如果文件不存在 直接返回
        }
        const int64_t& fileLen = IOUtil::getFileLen(f);
        char* buffer = new char[fileLen];
        IOUtil::byteRead(buffer, f, fileLen);
        initData(buffer, fileLen);
        MemUtil::asyncClearPtrArrMem(buffer);
    }


    virtual void writeToDisk(){
        char* buffer = getAllDataBuffer();
        IOUtil::byteWrite(buffer, resourceInfo.getFullPath(), delIndSet.size() * indSize);
        MemUtil::asyncClearPtrArrMem(buffer);
    }

    static void modBlockDelData(const Record* rec, fstream& f){
        int32_t numData = rec->opInd;
        f.seekp(0, ios::end);
        f.write((char*)&numData, sizeof (numData));
    }

    friend class ResourcePool; //需要从磁盘读数据
public:

    BlockDel(const ResourceInfo& resInfo):ResourceManage(resInfo){
        if(resInfo.getDiskType() != BLOCKDEL){
            throw string("diskType error");
        }
    }

    bool isDel(const int32_t& loc){  //返回是否删除
        return !(delIndSet.find(loc) == delIndSet.end()); //已被删除返回true
    }

    bool snapShotIsDel(const int32_t& loc){
        return !(snapShot.find(loc) == snapShot.end()); //已被删除返回true
    }

    void delEle(const int32_t& delInd){
        if(delIndSet.find(delInd) == delIndSet.end()){
            delIndSet.insert(delInd);
            additionDelIndList.push_back(delInd);
        }
    }

    void delEle(const vector<int32_t>& delIndVec){
        for(const int32_t& ind : delIndVec){
            delEle(ind);
        }
    }

    virtual vector<Record*> getComitRecords(){//为节约内存 获取时现创建记录
        makeSnapShot();
        vector<Record*> comitRecords;
        const string& baseName = resourceInfo.getBaseName();
        const string& tableName = resourceInfo.getTableName();
        const int16_t& blockNo = resourceInfo.getBlockNo();
        for(const int32_t& ind : additionDelIndList){
            comitRecords.push_back(new Record(baseName, tableName, "", blockNo, ind, DEL, nullptr, nullptr));
        }
        additionDelIndList.clear();
        return comitRecords;
    }

    virtual void memRollBack(){
        for(const int32_t& delInd : additionDelIndList){
            const auto& it = delIndSet.find(delInd);
            if(it != delIndSet.end()){
                delIndSet.erase(it);
            }
        }
        additionDelIndList.clear();
    };


    virtual void makeSnapShot(){
        getSnapShotLock(WRITE);
        for(const int32_t delInd : additionDelIndList){
            snapShot.insert(delInd);
        }
        releaseSnapShotLock();
    }

    //增量写入并释放record
    static void increWriteToDisk(const ResourceInfo& blockResInfo, const vector<Record*>& records){
        fstream f = IOUtil::getFstreamCreateIfNotExist(blockResInfo.getFullPath());
        for(Record* rec : records){
            modBlockDelData(rec, f);
        }
        f.close();
        MemUtil::asyncClearVecMem(records);
    }
};
